// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

#include "stdafx.h"
#include "WorldBuilder.h"
#include "MaterialManager.h"
#include "Material.h"


MaterialManager::MaterialManager()
{
    clear();
}

void MaterialManager::registerMaterial(ref<Material> mat)
{
    // If a material by that exists, don't do anything
    if(getMaterialByName(mat->getName()) != NULL)
    {
        ASSERT(false);
        return;
    }

    for(int i = 0; ; ++i)
    {
        if(m_usedIds.find(i) == m_usedIds.end())
        {
            mat->setId(i);
            m_usedIds.insert(i);
            m_materials.insert(mat);
            break;
        }
    }

    mat->setManager(this);
    
    ListenerIt it = m_listeners.begin();
    for(; it != m_listeners.end(); ++it)
    {
        MaterialListener* listener = *it;
		MaterialEvent event_(MaterialEvent::MaterialAdded);
		event_.manager = this;
		event_.material = mat.get(); 
        listener->onMaterialEvent(event_);
    }
}


std::wstring MaterialManager::generateNameFromPrefix(const std::wstring& prefix) const
{
    for(int i = 0; ; ++i) // Will eventually find an unused name
    {
        std::wostringstream oss;
        oss << prefix << i;
        if(getMaterialByName(oss.str()) != NULL)
        {
            return oss.str();
        }
    }
}

Material* MaterialManager::getMaterialById(int id) const
{
    // TODO this map should be the other way around for efficiency
    typedef MaterialSet::const_iterator It;
    for(It it = m_materials.begin(); it != m_materials.end(); ++it)
    {
        if((*it)->getId() == id)
        {
            return it->get();
        }
    }
    return NULL;
}

Material* MaterialManager::getMaterialByName(const std::wstring& name) const
{
    // TODO this map should be the other way around for efficiency
    typedef MaterialSet::const_iterator It;
    for(It it = m_materials.begin(); it != m_materials.end(); ++it)
    {
        if((*it)->getName() == name)
        {
            return it->get();
        }
    }
    return NULL;
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

void MaterialManager::clear()
{
    m_usedIds.clear();
    m_materials.clear();

    ref<Material> def(new Material);
    def->setName(L"default");
    registerMaterial(def);
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

Material* MaterialManager::getDefaultMaterial() const
{
    return getMaterialById(0);
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

MaterialManager::MaterialIt MaterialManager::beginMaterials() const
{
    return m_materials.begin();
}

MaterialManager::MaterialIt MaterialManager::endMaterials() const
{
    return m_materials.end();
}


size_t MaterialManager::getMaterialCount() const
{
    return m_materials.size();
}

// - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 

void MaterialManager::addMaterialListener(MaterialListener* listener)
{
    ASSERT(m_listeners.find(listener) == m_listeners.end());
    m_listeners.insert(listener);
}

void MaterialManager::removeMaterialListener(MaterialListener* listener)
{
    ASSERT(m_listeners.find(listener) != m_listeners.end());
    m_listeners.erase(listener);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
void MaterialManager::notifyMaterialAppearanceChanged(MaterialEvent& event_)
{
    ListenerIt it = m_listeners.begin();
    for(; it != m_listeners.end(); ++it)
    {
        MaterialListener* listener = *it;
		event_.manager = this;
        listener->onMaterialEvent(event_);
    }
}
